package com.sprouting.personal.utils;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.sprouting.personal.model.entity.*;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.lang.reflect.Field;
import java.util.List;

/**
 * 生成代码工具
 * 该工具类只针对mybatis-plus， 必须有 @TableId 主键来指定ID，且必须有id，使用者只需要关注 DefaultUpd 的参数即可生成相应代码
 *
 * @author ：LX（长沙麓谷）
 * @date 创建时间： 2023/3/26 12:11
 */
@Slf4j
public class GenerateTool {


    public static void main(String[] args) {
        GenerateTool.start();
    }

    /**
     * 用户默认修改区
     */
    interface DefaultUpd {
        /**
         * 要生成的model,必填
         */
        HomeworkRecord MODEL = new HomeworkRecord();
        /**
         * 文件注释,必填
         */
        String DOC = "家庭作业记录";
        /**
         * 逻辑删除属性,必填。获取属性，注意，这里现在是采用的int取值，没做属性的判断，后期非个人项目要注意这一块，否则sql可能进行转换
         */
        String LOGIC_DEL = "delType";
        /**
         * 逻辑删除属性，为新增的时候的值，用于 select * from xx where del = 0
         */
        String LOGIC_DEL_ADD = "0";
        /**
         * xml路径
         */
        String XML_PATH = "mapper/SQLite/";
        /**
         * dao层后缀，常用的有Mapper
         */
        String DAO_NAME = "Dao";


        /**
         * 是否读取父级属性,比如继承了 BaseModel
         */
        Boolean READ_PARENT = true;
        /**
         * 操作模式，预览还是写入，影响是否生成文件
         */
        Integer OPERATE = DefinePram.Operate.WRITE;

        /**
         * 数据库类型
         * 暂不考虑其他
         */
        Integer DB_TYPE = DefinePram.DbType.SQLITE;
        /**
         * 作者
         */
        String AUTHOR = "sprouting";
        /**
         * 是否生成实现层
         */
        Boolean IMPL = false;
        /**
         * 发现已有代码，是否覆盖
         */
        Boolean COVER = false;
        /**
         * 生成的风格
         * 暂不考虑 swagger
         */
        String STYLE = DefinePram.Style.MYBATIS_PLUS;
        /**
         * 要生成的查询方法，在集合中则生成
         */
        List<String> SUPPORTED_METHOD = CollUtil.newArrayList(
                DefinePram.SupportedMethod.GET_OBJ_BY_ID,
                DefinePram.SupportedMethod.GET_OBJ_PAGE,
                DefinePram.SupportedMethod.BATCH_INSERT);
    }

    /**
     * 定义的可选参数
     */
    interface DefinePram {
        /**
         * 操作
         */
        interface Operate {
            /**
             * 预览，将生成的文件预览效果
             */
            Integer VIEW = 1;
            /**
             * 写出
             */
            Integer WRITE = 2;
        }
        /**
         * 数据库类型
         */
        interface DbType {
            Integer MYSQL = 1;
            Integer SQLITE = 2;
        }
        /**
         * 支持的方法
         */
        interface SupportedMethod {
            /**
             * 根据主键查询
             */
            String GET_OBJ_BY_ID = "getObjById";
            /**
             * 分页查询
             */
            String GET_OBJ_PAGE = "getObjPage";
            /**
             * 批量插入
             */
            String BATCH_INSERT = "batchInsert";
        }
        /**
         * 风格
         */
        interface Style {
            /**
             * 默认的mybatis
             */
            String MYBATIS_PLUS = "mybatis-plus";
            /**
             * swagger 注释版本
             */
            String SWAGGER = "swagger";
        }
    }


    /**
     * 换行
     */
    public static final String ENTER = "\n";
    /**
     * tab空格
     */
    public static final String TAB = "\t";



    /**
     * 开始点
     */
    public static void start(){
        String controllerText = controller();

        String serviceText = null;
        if (DefaultUpd.IMPL){
            serviceText = service();
        }
        String serviceImplText = serviceImpl();
        String daoText = dao();
        String xmlText = xml();

        writePath(controllerText, serviceText, serviceImplText, daoText, xmlText);
    }


    /**
     * 写入文件并指定路径
     * @param controllerText 控制层内容
     * @param serviceText service接口内容
     * @param serviceImplText serviceImpl 实现内容
     * @param daoText dao层内容
     * @param xmlText xml文件内容
     */
    private static void writePath(String controllerText, String serviceText, String serviceImplText, String daoText, String xmlText){
        // model类的前一级
        String parentPath = getParentPackageName();
        // model的上一级的路径
        String replace = parentPath.replace(".", "\\");
        String srcPath = getBasePath() + "\\src\\main\\java\\" + replace;

        // 第一个参数，包，比如 service，dao 层包名，第二个参数，类名。
        // 参数1， 包名，com.xx.aa.bb bb就是要这里的包名
        // 参数2， 类名，比如 xxController， xxDao ,后面的dao就是要写的
        String simplePathName = srcPath + "/%s/" + getSimpleClassName() + "%s.java";

        write(controllerText, String.format(simplePathName, "controller", "Controller"));
        write(serviceText, String.format(simplePathName, "service", "Service"));

        if (DefaultUpd.IMPL){
            write(serviceImplText, String.format(simplePathName, "service/impl", "ServiceImpl"));
        } else {
            write(serviceImplText, String.format(simplePathName, "service", "Service"));
        }

        write(daoText, String.format(simplePathName, DefaultUpd.DAO_NAME.toLowerCase(), DefaultUpd.DAO_NAME));

        // 单独处理xml的文件,路径不一样
        String xmlPath = getBasePath() + "/src/main/resources/" + DefaultUpd.XML_PATH + getSimpleClassName() + DefaultUpd.DAO_NAME + ".xml";
        write(xmlText, xmlPath);
    }

    /**
     * 写出类文件
     * @param txt 要写入的文字
     * @param finalPath 最终写出的路径
     */
    private static void write(String txt, String finalPath){
        if (StrUtil.isEmpty(txt)){
            return;
        }

        out("生成文件：========>" + finalPath);

        if (DefaultUpd.OPERATE.equals(DefinePram.Operate.VIEW)){
            out("预览模式,不写出=>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            out("预览模式,不写出=>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            out("预览模式,不写出=>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            return;
        }

        if (FileUtil.exist(finalPath)){
            if (DefaultUpd.COVER){
                // 覆盖

            } else {
                // 不覆盖，也不需要往后继续了
                return;
            }
        } else {
            // 不存在
        }

        File touch = FileUtil.touch(finalPath);
        FileUtil.writeUtf8String(txt, touch);
    }


    /**
     * 控制层
     */
    private static String controller(){
        StringBuilder content = new StringBuilder();

        content.append("package ").append(getParentPackageName()).append(".").append("controller").append(";");
        content.append(ENTER);
        content.append(ENTER);

        String className = getClassName();
        String simpleClassName = getSimpleClassName();
        // 首字母小写
        String lowercaseFirstLetter = getLowercaseFirstLetter();

        // model
        content.append("import ").append(className).append(";").append(ENTER);
        // service
        content.append("import ").append(getParentPackageName()).append(".").append("service.").append(simpleClassName).append("Service").append(";").append(ENTER);

        content.append("import com.baomidou.mybatisplus.extension.plugins.pagination.Page;").append(ENTER);
        content.append("import lombok.extern.slf4j.Slf4j;").append(ENTER);
        content.append("import org.springframework.beans.factory.annotation.Autowired;").append(ENTER);
        content.append("import org.springframework.web.bind.annotation.PostMapping;").append(ENTER);
        content.append("import org.springframework.web.bind.annotation.RequestMapping;").append(ENTER);
        content.append("import org.springframework.web.bind.annotation.RestController;").append(ENTER);
        content.append(ENTER);

        content.append("import java.util.List").append(";").append(ENTER);
        content.append(ENTER);

        content.append("/**").append(ENTER);
        content.append(" * ").append(DefaultUpd.DOC).append(" 控制层").append(ENTER);
        content.append(" *").append(ENTER);
        content.append(" * @author ：").append(DefaultUpd.AUTHOR).append(ENTER);
        content.append(" * @date 创建时间： ").append(DateUtil.now()).append(ENTER);
        content.append(" */").append(ENTER);
        content.append("@Slf4j").append(ENTER);
        content.append("@RestController").append(ENTER);
        content.append("@RequestMapping(\"").append(lowercaseFirstLetter).append("\")").append(ENTER);
        content.append("public class ").append(simpleClassName).append("Controller {").append(ENTER);
        content.append(ENTER);

        String serviceName = lowercaseFirstLetter + "Service";

        content.append(TAB).append("@Autowired").append(ENTER);
        content.append(TAB).append("private ").append(simpleClassName).append("Service ").append(serviceName).append(";").append(ENTER);
        content.append(ENTER);
        content.append("}");

        out(content.toString());
        return content.toString();
    }


    /**
     * 接口层
     */
    private static String service(){
        StringBuilder content = new StringBuilder();

        content.append("package ").append(getParentPackageName()).append(".").append("service;");
        content.append(ENTER);
        content.append(ENTER);

        String className = getClassName();
        String simpleClassName = getSimpleClassName();
        // 首字母小写
        String lowercaseFirstLetter = getLowercaseFirstLetter();

        content.append("import com.baomidou.mybatisplus.extension.plugins.pagination.Page;").append(ENTER);
        content.append("import com.baomidou.mybatisplus.extension.service.IService;").append(ENTER);
        content.append("import ").append(className).append(";").append(ENTER);
        content.append(ENTER);

        content.append("import java.util.List").append(";").append(ENTER);
        content.append(ENTER);

        content.append("/**").append(ENTER);
        content.append(" * ").append(DefaultUpd.DOC).append(" service接口").append(ENTER);
        content.append(" *").append(ENTER);
        content.append(" * @author ：").append(DefaultUpd.AUTHOR).append(ENTER);
        content.append(" * @date 创建时间： ").append(DateUtil.now()).append(ENTER);
        content.append(" */").append(ENTER);
        content.append("public interface ").append(simpleClassName).append("Service").append(" extends IService<").append(simpleClassName).append("> {").append(ENTER);
        content.append(ENTER);

        // 根据主键查询单条数据
        if (DefaultUpd.SUPPORTED_METHOD.contains(DefinePram.SupportedMethod.GET_OBJ_BY_ID)){
            content.append(TAB).append("/**").append(ENTER);
            content.append(TAB).append(" * 通过ID查询单条数据").append(ENTER);
            content.append(TAB).append(" * @param ").append(getId()).append(" 主键").append(ENTER);
            content.append(TAB).append(" * @return ").append(DefaultUpd.DOC).append(ENTER);
            content.append(TAB).append(" */").append(ENTER);
            String simpleTypeName = getFieldSimpleName(getId());
            content.append(TAB).append(simpleClassName).append(" ").append(getById()).append("(").append(simpleTypeName).append(" ").append(getId()).append(");").append(ENTER);
            content.append(ENTER);
        }

        // 批量新增
        if (DefaultUpd.SUPPORTED_METHOD.contains(DefinePram.SupportedMethod.BATCH_INSERT)){
            content.append(TAB).append("/**").append(ENTER);
            content.append(TAB).append(" * 批量新增数据（MyBatis原生foreach方法）").append(ENTER);
            content.append(TAB).append(" * @param list 实例对象列表").append(ENTER);
            content.append(TAB).append(" */").append(ENTER);
            content.append(TAB).append("void ").append(getInsertBatch()).append("(List<").append(simpleClassName).append("> list);").append(ENTER);
            content.append(ENTER);
        }

        // 分页查询
        if (DefaultUpd.SUPPORTED_METHOD.contains(DefinePram.SupportedMethod.GET_OBJ_PAGE)){
            content.append(TAB).append("/**").append(ENTER);
            content.append(TAB).append(" * 分页查询").append(ENTER);
            content.append(TAB).append(" * @param page 分页参数").append(ENTER);
            content.append(TAB).append(" * @param ").append(lowercaseFirstLetter).append(" 查询参数").append(ENTER);
            content.append(TAB).append(" * @return 条件查询结果").append(ENTER);
            content.append(TAB).append(" */").append(ENTER);
            content.append(TAB).append("Page<").append(simpleClassName).append("> ").append(getPage()).append("(Page page, ").append(simpleClassName).append(" ").append(lowercaseFirstLetter).append(");").append(ENTER);
            content.append(ENTER);
        }

        content.append("}");

        out(content.toString());
        return content.toString();
    }

    /**
     * service实现层 impl
     */
    private static String serviceImpl(){
        StringBuilder content = new StringBuilder();

        content.append("package ").append(getParentPackageName()).append(".").append("service");
        if (DefaultUpd.IMPL){
            content.append(".impl");
        }
        content.append(";");
        content.append(ENTER);
        content.append(ENTER);

        String className = getClassName();
        String simpleClassName = getSimpleClassName();
        // 首字母小写
        String lowercaseFirstLetter = getLowercaseFirstLetter();

        // model
        content.append("import ").append(className).append(";").append(ENTER);
        // dao
        content.append("import ").append(getParentPackageName()).append(".");
        content.append(DefaultUpd.DAO_NAME.toLowerCase()).append(".");
        content.append(simpleClassName).append(DefaultUpd.DAO_NAME);
        content.append(";").append(ENTER);
        // service
        if (DefaultUpd.IMPL){
            content.append("import ").append(getParentPackageName()).append(".").append("service.").append(simpleClassName).append("Service;").append(ENTER);
        }

        content.append("import com.baomidou.mybatisplus.extension.plugins.pagination.Page;").append(ENTER);
        content.append("import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;").append(ENTER);
        content.append("import lombok.extern.slf4j.Slf4j;").append(ENTER);
        content.append("import org.springframework.stereotype.Service;").append(ENTER);
        content.append(ENTER);

        content.append("import javax.annotation.Resource").append(";").append(ENTER);
        content.append("import java.util.List").append(";").append(ENTER);
        content.append(ENTER);

        content.append("/**").append(ENTER);
        content.append(" * ").append(DefaultUpd.DOC).append(" service接口实现").append(ENTER);
        content.append(" *").append(ENTER);
        content.append(" * @author ：").append(DefaultUpd.AUTHOR).append(ENTER);
        content.append(" * @date 创建时间： ").append(DateUtil.now()).append(ENTER);
        content.append(" */").append(ENTER);
        content.append("@Service").append(ENTER);
        content.append("@Slf4j").append(ENTER);
        content.append("public class ").append(simpleClassName).append("Service");
        if (DefaultUpd.IMPL){
            content.append("Impl");
        }
        content.append(" extends ServiceImpl<").append(simpleClassName).append(DefaultUpd.DAO_NAME).append(", ").append(simpleClassName).append(">");
        if (DefaultUpd.IMPL){
            content.append(" implements ").append(simpleClassName).append("Service");
        }
        content.append(" {").append(ENTER);
        content.append(ENTER);

        String daoName = lowercaseFirstLetter + DefaultUpd.DAO_NAME;

        content.append(TAB).append("@Resource").append(ENTER);
        content.append(TAB).append("private ").append(simpleClassName).append(DefaultUpd.DAO_NAME).append(" ").append(daoName).append(";").append(ENTER);
        content.append(ENTER);

        // 根据主键查询单条数据
        if (DefaultUpd.SUPPORTED_METHOD.contains(DefinePram.SupportedMethod.GET_OBJ_BY_ID)){
            content.append(TAB).append("/**").append(ENTER);
            content.append(TAB).append(" * 通过ID查询单条数据").append(ENTER);
            content.append(TAB).append(" * @param ").append(getId()).append(" 主键").append(ENTER);
            content.append(TAB).append(" * @return ").append(DefaultUpd.DOC).append(ENTER);
            content.append(TAB).append(" */").append(ENTER);
            String simpleTypeName = getFieldSimpleName(getId());
            if (DefaultUpd.IMPL){
                content.append(TAB).append("@Override").append(ENTER);
            }
            content.append(TAB).append("public ").append(simpleClassName).append(" ").append(getById()).append("(").append(simpleTypeName).append(" ").append(getId()).append(") {").append(ENTER);
            content.append(TAB).append(TAB).append("return ").append(daoName).append(".").append(getById()).append("(").append(getId()).append(");").append(ENTER);
            content.append(TAB).append("}").append(ENTER);
            content.append(ENTER);
        }

        // 批量新增
        if (DefaultUpd.SUPPORTED_METHOD.contains(DefinePram.SupportedMethod.BATCH_INSERT)){
            content.append(TAB).append("/**").append(ENTER);
            content.append(TAB).append(" * 批量新增数据（MyBatis原生foreach方法）").append(ENTER);
            content.append(TAB).append(" * @param list 实例对象列表").append(ENTER);
            content.append(TAB).append(" */").append(ENTER);
            if (DefaultUpd.IMPL){
                content.append(TAB).append("@Override").append(ENTER);
            }
            content.append(TAB).append("public void ").append(getInsertBatch()).append("(List<").append(simpleClassName).append("> list){").append(ENTER);
            content.append(TAB).append(TAB).append(daoName).append(".").append(getInsertBatch()).append("(list);").append(ENTER);
            content.append(TAB).append("}").append(ENTER);
            content.append(ENTER);
        }

        // 分页查询
        if (DefaultUpd.SUPPORTED_METHOD.contains(DefinePram.SupportedMethod.GET_OBJ_PAGE)){
            content.append(TAB).append("/**").append(ENTER);
            content.append(TAB).append(" * 分页查询").append(ENTER);
            content.append(TAB).append(" * @param page 分页参数").append(ENTER);
            content.append(TAB).append(" * @param ").append(lowercaseFirstLetter).append(" 查询参数").append(ENTER);
            content.append(TAB).append(" * @return 条件查询结果").append(ENTER);
            content.append(TAB).append(" */").append(ENTER);
            if (DefaultUpd.IMPL){
                content.append(TAB).append("@Override").append(ENTER);
            }
            content.append(TAB).append("public Page<").append(simpleClassName).append("> ").append(getPage()).append("(Page page, ").append(simpleClassName).append(" ").append(lowercaseFirstLetter).append("){").append(ENTER);
            content.append(TAB).append(TAB).append("return ").append(daoName).append(".").append(getPage()).append("(page, ").append(lowercaseFirstLetter).append(");").append(ENTER);
            content.append(TAB).append("}").append(ENTER);
            content.append(ENTER);
        }

        content.append("}");

        out(content.toString());
        return content.toString();
    }


    /**
     * 构建dao层
     */
    private static String dao(){
        StringBuilder content = new StringBuilder();
        content.append("package ").append(getParentPackageName()).append(".");
        content.append(DefaultUpd.DAO_NAME.toLowerCase());
        content.append(";");
        content.append(ENTER);
        content.append(ENTER);

        content.append("import org.apache.ibatis.annotations.Param;").append(ENTER);
        content.append("import com.baomidou.mybatisplus.core.mapper.BaseMapper").append(";").append(ENTER);
        content.append("import com.baomidou.mybatisplus.extension.plugins.pagination.Page;").append(ENTER);
        content.append("import ").append(getClassName()).append(";").append(ENTER);
        content.append(ENTER);

        content.append("import java.util.List").append(";").append(ENTER);
        content.append(ENTER);

        content.append("/**").append(ENTER);
        content.append(" * ").append(DefaultUpd.DOC).append(" dao").append(ENTER);
        content.append(" *").append(ENTER);
        content.append(" * @author ：").append(DefaultUpd.AUTHOR).append(ENTER);
        content.append(" * @date 创建时间： ").append(DateUtil.now()).append(ENTER);
        content.append(" */").append(ENTER);

        String simpleClassName = getSimpleClassName();
        // 首字母小写
        String lowercaseFirstLetter = getLowercaseFirstLetter();

        content.append("public interface ").append(simpleClassName).append(DefaultUpd.DAO_NAME).append(" extends BaseMapper<").append(simpleClassName).append("> {").append(ENTER);
        content.append(ENTER);

        // 根据主键查询单条数据
        if (DefaultUpd.SUPPORTED_METHOD.contains(DefinePram.SupportedMethod.GET_OBJ_BY_ID)){
            content.append(TAB).append("/**").append(ENTER);
            content.append(TAB).append(" * 通过ID查询单条数据").append(ENTER);
            content.append(TAB).append(" * @param ").append(getId()).append(" 主键").append(ENTER);
            content.append(TAB).append(" * @return ").append(DefaultUpd.DOC).append(ENTER);
            content.append(TAB).append(" */").append(ENTER);
            String simpleTypeName = getFieldSimpleName(getId());
            content.append(TAB).append(simpleClassName).append(" ").append(getById()).append("(").append(simpleTypeName).append(" ").append(getId()).append(");").append(ENTER);
            content.append(ENTER);
        }

        // 批量新增
        if (DefaultUpd.SUPPORTED_METHOD.contains(DefinePram.SupportedMethod.BATCH_INSERT)){
            content.append(TAB).append("/**").append(ENTER);
            content.append(TAB).append(" * 批量新增数据（MyBatis原生foreach方法）").append(ENTER);
            content.append(TAB).append(" * @param list 实例对象列表").append(ENTER);
            content.append(TAB).append(" */").append(ENTER);
            content.append(TAB).append("void ").append(getInsertBatch()).append("(@Param(\"list\") List<").append(simpleClassName).append("> list);").append(ENTER);
            content.append(ENTER);
        }

        // 分页查询
        if (DefaultUpd.SUPPORTED_METHOD.contains(DefinePram.SupportedMethod.GET_OBJ_PAGE)){
            content.append(TAB).append("/**").append(ENTER);
            content.append(TAB).append(" * 分页查询").append(ENTER);
            content.append(TAB).append(" * @param page 分页参数").append(ENTER);
            content.append(TAB).append(" * @param ").append(lowercaseFirstLetter).append(" 查询参数").append(ENTER);
            content.append(TAB).append(" * @return 条件查询结果").append(ENTER);
            content.append(TAB).append(" */").append(ENTER);
            content.append(TAB).append("Page<").append(simpleClassName).append("> ").append(getPage()).append("(Page page, @Param(\"entity\") ").append(simpleClassName).append(" ").append(lowercaseFirstLetter).append(");").append(ENTER);
            content.append(ENTER);
        }

        content.append("}");

        out(content.toString());
        return content.toString();
    }

    /**
     * xml代码生成
     */
    private static String xml(){
        // 文本
        StringBuilder content = new StringBuilder();
        content.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>").append(ENTER);
        content.append("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\" >").append(ENTER);
        String className = ClassUtil.getClassName(DefaultUpd.MODEL, false);
        content.append("<mapper namespace=\"").append(getParentPackageName()).append(".").append(DefaultUpd.DAO_NAME.toLowerCase()).append(".").append(getSimpleClassName()).append(DefaultUpd.DAO_NAME).append("\">").append(ENTER);
        content.append(ENTER);

        String simpleClassName = getSimpleClassName();
        // 首字母小写
        String lowercaseFirstLetter = getLowercaseFirstLetter();

        // 根据主键查询单条数据
        if (DefaultUpd.SUPPORTED_METHOD.contains(DefinePram.SupportedMethod.GET_OBJ_BY_ID)){
            content.append(TAB).append("<select id=\"").append("get").append(simpleClassName).append("ById\" resultType=\"").append(className).append("\">").append(ENTER);
            content.append(TAB).append(TAB).append("select * from ").append(getTableName()).append(" where ");
            if (StrUtil.isNotEmpty(DefaultUpd.LOGIC_DEL)){
                // 转为驼峰
                content.append(StrUtil.toUnderlineCase(DefaultUpd.LOGIC_DEL)).append(" = ").append(DefaultUpd.LOGIC_DEL_ADD).append(" and ");
            }
            content.append(getIdTable()).append(" = #{").append(getId()).append("}").append(ENTER);
            content.append(TAB).append("</select>").append(ENTER);
            content.append(ENTER);
        }

        // 批量新增
        if (DefaultUpd.SUPPORTED_METHOD.contains(DefinePram.SupportedMethod.BATCH_INSERT)){
            content.append(TAB).append("<insert id=\"").append("insertBatch").append(simpleClassName).append("\">").append(ENTER);
            content.append(TAB).append(TAB).append("insert into ").append(getTableName()).append(ENTER);
            content.append(TAB).append(TAB).append("(");
            // 所有属性
            Field[] fields;
            if (DefaultUpd.READ_PARENT){
                // 读取父类
                fields = ReflectUtil.getFields(DefaultUpd.MODEL.getClass());
            } else {
                fields = ReflectUtil.getFieldsDirectly(DefaultUpd.MODEL.getClass(), false);
            }
            // 字段
            StringBuilder fieldNameSQL = new StringBuilder();
            // 插入
            StringBuilder fieldValueSQL = new StringBuilder();
            for (int i = 0; i < fields.length; i++) {
                Field field = fields[i];
                String name = field.getName();
                // 转驼峰
                String underlineCaseName = StrUtil.toUnderlineCase(name);
                fieldNameSQL.append(underlineCaseName);
                fieldValueSQL.append("#{entity.").append(name).append("}");
                if (i != (fields.length - 1)){
                    fieldNameSQL.append(", ");
                    fieldValueSQL.append(", ");
                }
            }
            content.append(fieldNameSQL).append(")").append(ENTER);
            content.append(TAB).append(TAB).append("values").append(ENTER);
            content.append(TAB).append(TAB).append("<foreach collection=\"list\" item=\"entity\" separator=\",\">").append(ENTER);
            content.append(TAB).append(TAB).append(TAB).append("(").append(fieldValueSQL).append(")").append(ENTER);
            content.append(TAB).append(TAB).append("</foreach>").append(ENTER);
            content.append(TAB).append("</insert>").append(ENTER);
            content.append(ENTER);
        }

        // 分页查询
        if (DefaultUpd.SUPPORTED_METHOD.contains(DefinePram.SupportedMethod.GET_OBJ_PAGE)){
            content.append(TAB).append("<select id=\"").append("get").append(simpleClassName).append("Page\" resultType=\"").append(className).append("\">").append(ENTER);
            content.append(TAB).append(TAB).append("select * from ").append(getTableName()).append(ENTER);
            content.append(TAB).append(TAB).append("where 1 = 1");
            if (StrUtil.isNotEmpty(DefaultUpd.LOGIC_DEL)) {
                content.append(" and ").append(StrUtil.toUnderlineCase(DefaultUpd.LOGIC_DEL)).append(" = ").append(DefaultUpd.LOGIC_DEL_ADD).append(ENTER);
            }
            // 所有属性
            Field[] fields;
            if (DefaultUpd.READ_PARENT){
                // 读取父类
                fields = ReflectUtil.getFields(DefaultUpd.MODEL.getClass());
            } else {
                fields = ReflectUtil.getFieldsDirectly(DefaultUpd.MODEL.getClass(), false);
            }
            for (int i = 0; i < fields.length; i++) {
                Field field = fields[i];
                String name = field.getName();
                String typeName = field.getGenericType().getTypeName();
                // 转驼峰
                String underlineCaseName = StrUtil.toUnderlineCase(name);

                // 主键不加入到分页查询中
                if (underlineCaseName.equals(getId())){
                    continue;
                }

                // 暂不支持非string类型的，id如果为非该string的，也可能出错
                if ("java.lang.String".equals(typeName)){
                    content.append(TAB).append(TAB).append("<if test=\"entity.").append(name).append(" != null and entity.").append(name).append(" != '' \">").append(ENTER);
                    content.append(TAB).append(TAB).append(TAB).append("and ").append(underlineCaseName).append(" = #{entity.").append(name).append("}").append(ENTER);
                    content.append(TAB).append(TAB).append("</if>").append(ENTER);

                } else if ("java.lang.Integer".equals(typeName)){
                    content.append(TAB).append(TAB).append("<if test=\"entity.").append(name).append(" != null\">").append(ENTER);
                    content.append(TAB).append(TAB).append(TAB).append("and ").append(underlineCaseName).append(" = #{entity.").append(name).append("}").append(ENTER);
                    content.append(TAB).append(TAB).append("</if>").append(ENTER);
                }
            }
            content.append(TAB).append("</select>").append(ENTER);
            content.append(ENTER);
        }

        content.append("</mapper>").append(ENTER);

        out(content.toString());
        return content.toString();
    }

    /**
     * 获取model中某个属性的类名，比如属性 String id, 传入id 后得到 String
     * @param fieldName 属性名
     * @return
     */
    private static String getFieldSimpleName(String fieldName){
        Field fieldId = ReflectUtil.getField(DefaultUpd.MODEL.getClass(), fieldName);
        String typeName = fieldId.getGenericType().getTypeName();
        return typeName.substring(typeName.lastIndexOf(".") + 1);
    }

    /**
     * 获取model中某个属性的类名，比如属性 String id, 传入id 后得到 java.lang.String
     * @param fieldName 属性名
     * @return
     */
    private static String getFieldName(String fieldName){
        Field fieldId = ReflectUtil.getField(DefaultUpd.MODEL.getClass(), fieldName);
        return fieldId.getGenericType().getTypeName();
    }

    /**
     * 获取首字母小写，比如 UploadAdmin 得到 uploadAdmin
     * @return
     */
    private static String getLowercaseFirstLetter(){
        String simpleClassName = ClassUtil.getClassName(DefaultUpd.MODEL, true);
        // 首字母小写
        String lowerCaseFirstChar = String.valueOf(simpleClassName.charAt(0)).toLowerCase();
        return lowerCaseFirstChar + simpleClassName.substring(1);
    }

    /**
     * 获取类名，一个类名如 com.sprouting.personal.model.entity.Movies
     * @return
     */
    private static String getClassName(){
        return ClassUtil.getClassName(DefaultUpd.MODEL, false);
    }

    /**
     * 获取简单类名，比如 com.sprouting.personal.model.entity.Movies 得到 Movies
     * @return
     */
    private static String getSimpleClassName(){
        return ClassUtil.getClassName(DefaultUpd.MODEL, true);
    }


    /**
     * 获取上一级包名,比如, com.sprouting.personal.service.dao 获得 com.sprouting.personal
     * @return
     */
    private static String getParentPackageName(){
        String aPackage = ClassUtil.getPackage(DefaultUpd.MODEL.getClass());
        // 上一级包名
        // 获取最后一个"."字符的索引
        int lastIndex = aPackage.lastIndexOf(".");
        // 获取上一级包名
        return aPackage.substring(0, lastIndex);
    }

    /**
     * 输出展示
     * @param content 文档
     */
    private static void out(String content){
        System.out.println(getFormatLogString(content,33, 0));
    }

    /**
     * 输出带颜色的文字-控制台
     * [ 红色 ]", 31, 0
     * [ 黄色 ]", 32, 0
     * [ 橙色 ]", 33, 0
     * "[ 蓝色 ]", 34, 0
     * [ 紫色 ]", 35, 0)
     * [ 绿色 ]", 36, 0
     *
     * @param colour  颜色代号：背景颜色代号(41-46)；前景色代号(31-36)
     * @param type    样式代号：0无；1加粗；3斜体；4下划线
     * @param content 要打印的内容
     */
    private static String getFormatLogString(String content, int colour, int type) {
        boolean hasType = type != 1 && type != 3 && type != 4;
        if (hasType) {
            return String.format("\033[%dm%s\033[0m", colour, content);
        } else {
            return String.format("\033[%d;%dm%s\033[0m", colour, type, content);
        }
    }

    /**
     * 获取通过id查询名称
     * @return
     */
    private static String getById(){
        return "get" + getSimpleClassName() + "ById";
    }

    /**
     * 获取 批量新增
     * @return
     */
    private static String getInsertBatch(){
        return "insertBatch" + getSimpleClassName();
    }

    /**
     * 获取 分页查询
     * @return
     */
    private static String getPage(){
        return "get" + getSimpleClassName() + "Page";
    }

    /**
     * 返回基础路径
     * @return target 层
     */
    private static String getBasePath(){
        // 得到target下的classes路径
        String classPath = ClassUtil.getClassPath();
        // 向上级2层，获取 比如：E:\kaiFa\IDEATest\bud\bud-server\（target这一级）\src\main\java
        return FileUtil.getParent(classPath, 2);
    }

    /**
     * 获取表名，如果没有 @TableName 注解，则使用类名，否则使用注解中的表名
     * @return
     */
    private static String getTableName(){
        TableName tableName = AnnotationUtil.getAnnotation(DefaultUpd.MODEL.getClass(), TableName.class);
        if (tableName != null){
            String value = tableName.value();
            if (StrUtil.isNotEmpty(value)){
                // 表明
                return value;
            }
        }

        // 如果没有注解，就使用model名称，并使用驼峰
        String simpleClassName = getSimpleClassName();
        return StrUtil.toUnderlineCase(simpleClassName);
    }

    /**
     * 获取ID表字段名，查找 @TableId 注解，注解中有参数则使用参数，否则使用该属性，未查询到则抛出异常
     * 需要注意的是，暂不支持多个id的情况
     * @return
     */
    private static String getIdTable(){
        Field[] fields = ReflectUtil.getFields(DefaultUpd.MODEL.getClass());
        Field idField = null;
        for (Field field : fields){
            TableId annotation = field.getAnnotation(TableId.class);
            if (annotation != null){
                // 注解中给了则使用，否则不使用
                String valueField = annotation.value();
                if (StrUtil.isNotEmpty(valueField)){
                    // 暂时只支持单个，不支持多个id,直接返回标记的id
                    return valueField;
                }
                // 发现了id注解，但没有指定
                idField = field;
                // 已经发现了一个，终止查询，暂不支持多ID的情况
                break;
            }
        }

        if (idField == null){
            throw new IllegalArgumentException("未查询到ID属性，请确保存在@TableId 注解");
        }
        String id = idField.getName();
        return StrUtil.toUnderlineCase(id);
    }

    /**
     * 获取ID属性，非字段，查找 @TableId 注解，然后查找对应的属性
     * 需要注意的是，暂不支持多个id的情况
     * @return
     */
    private static String getId(){
        Field[] fields = ReflectUtil.getFields(DefaultUpd.MODEL.getClass());
        Field idField = null;
        for (Field field : fields){
            TableId annotation = field.getAnnotation(TableId.class);
            if (annotation != null){
                // 发现了id注解，但没有指定
                idField = field;
                // 已经发现了一个，终止查询，暂不支持多ID的情况
                break;
            }
        }

        if (idField == null){
            throw new IllegalArgumentException("未查询到ID属性，请确保存在@TableId 注解");
        }
        String id = idField.getName();
        return StrUtil.toUnderlineCase(id);
    }
}

